package com.zg.nacos.web;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zg.common.core.R;
import com.zg.common.core.util.JsonUtil;
import com.zg.nacos.domain.req.*;
import com.zg.nacos.domain.vo.ClusterVo;
import com.zg.nacos.domain.vo.ServiceDetailVo;
import com.zg.nacos.domain.vo.ServiceVo;
import com.zg.nacos.util.NacosUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import javax.validation.Valid;
import java.time.Duration;
import java.util.List;
import java.util.Map;

/**
 * <p>Description: </p>
 *
 * @author zhanfeng.liang
 * @since 2025/6/20 16:11
 */

@RestController
@RequestMapping("/nacos")
@Api(tags = "nacos服务")
@Slf4j
public class NacosServiceController {


    @Autowired
    private WebClient webClient;
    /**
     * 服务列表
     * @param servicesPageReq
     * @return
     */
    @ApiOperation(value="服务列表")
    @PostMapping("/service/page")
    public R pageServices(@Valid @RequestBody ServicesPageReq servicesPageReq) throws Exception{
        return webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("/nacos/v1/ns/catalog/services")
                        .queryParam("namespaceId", servicesPageReq.getNamespaceId())
                        .queryParam("pageNo", servicesPageReq.getPageNo())
                        .queryParam("pageSize", servicesPageReq.getPageSize())
                        .queryParam("accessToken",servicesPageReq.getNacosToken())
                        .build())
//                .header("username", userName)
//                .header("password", password)
                .retrieve()
                .bodyToMono(Map.class)
                .map(nacosResponse -> {
                    List<Map<String, Object>> serviceList = (List<Map<String, Object>>) nacosResponse.get("serviceList");
                    serviceList.forEach(item -> {
                        item.put("namespaceId",  servicesPageReq.getNamespaceId());
                    });

                    Integer total = (Integer) nacosResponse.get("count");

                    // 构建MyBatis-Plus的Page对象
                    Page<Map<String, Object>> page = new Page<>(servicesPageReq.getPageNo(), servicesPageReq.getPageSize(), total);
                    page.setRecords(serviceList);
                    // 转换为 R 格式
                    return R.success(page);
                })
                .block(Duration.ofSeconds(5));
    }

    /**
     * 服务详情
     * @param servicesPageReq
     * @return
     */
    @ApiOperation(value="服务详情")
    @PostMapping("/service/info")
    public R<ServiceDetailVo> getService(@Valid @RequestBody ServiceInfoReq servicesPageReq) {
        return webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("/nacos/v1/ns/catalog/service")
                        .queryParam("serviceName", servicesPageReq.getName())
                        .queryParam("groupName", servicesPageReq.getGroupName())
                        .queryParam("namespaceId",servicesPageReq.getNamespaceId())
                        .queryParam("accessToken",servicesPageReq.getNacosToken())
                        .build())
//                .header("username", userName)
//                .header("password", password)
                .retrieve()
                .bodyToMono(Map.class)
                .map(nacosResponse -> {
                    Map data = (Map)nacosResponse.get("service");
                    ServiceVo serviceVo =JsonUtil.convertObj(data, ServiceVo.class);
                    serviceVo.setNamespaceId(servicesPageReq.getNamespaceId());

                    List<Map> clusters = (List<Map>)nacosResponse.get("clusters");

                    ServiceDetailVo vo = new ServiceDetailVo();

                    vo.setService(serviceVo);
                    List<ClusterVo> list = JsonUtil.convertList(clusters,ClusterVo.class);
                    vo.setClusters(list);

                    // 转换为 R 格式
                    return R.success(vo);
                }).block(Duration.ofSeconds(5));
    }

    /**
     * 服务编辑
     * @param serviceEditReq
     * @return
     */
    @ApiOperation(value="服务编辑")
    @PostMapping("/service/edit")
    public R editService(@Valid @RequestBody ServiceEditReq serviceEditReq) {
        MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();

        // 使用add方法添加表单字段（更适合multipart/form-data）
        formData.add("serviceName", serviceEditReq.getName());
        formData.add("groupName", serviceEditReq.getGroupName());
        formData.add("namespaceId", serviceEditReq.getNamespaceId());
        formData.add("protectThreshold", serviceEditReq.getProtectThreshold());
        formData.add("metadata", JsonUtil.toJson(serviceEditReq.getMetadata()));
        String jsonValue = "{\"type\":\"none\",\"labels\":[],\"contextType\":\"CMDB\"}";

        formData.add("selector", jsonValue);
        return webClient.put()
                .uri(uriBuilder -> uriBuilder
                        .path("/nacos/v1/ns/service")
                        .queryParam("accessToken",serviceEditReq.getNacosToken())
                        .build())
//                .header("username", userName)
//                .header("password", password)
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .body(BodyInserters.fromMultipartData(formData))
                .retrieve()
                .bodyToMono(String.class)
                .map(nacosResponse -> {
                    // 转换为 R 格式
                    return R.success(nacosResponse);
                }).block(Duration.ofSeconds(5));
    }
    /**
     * 实例列表
     * @param instancePageReq
     * @return
     */
    @ApiOperation(value="实例列表")
    @PostMapping("/instance/page")
    public R pageInstance(@Valid @RequestBody InstancePageReq instancePageReq) {
        if(StrUtil.isEmpty(instancePageReq.getNamespaceId())||StrUtil.isEmpty(instancePageReq.getServiceName())){
            Page<Map> page = new Page<>(instancePageReq.getPageNo(), instancePageReq.getPageSize(), 0);
            page.setRecords(Lists.newArrayList());
            // 转换为 R 格式
            return R.success(page);
        }
        return webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("/nacos/v1/ns/catalog/instances")
                        .queryParam("serviceName", instancePageReq.getServiceName())
                        .queryParam("groupName", instancePageReq.getGroupName())
                        .queryParam("namespaceId",instancePageReq.getNamespaceId())
                        .queryParam("clusterName",instancePageReq.getClusterName())
                        .queryParam("pageNo", instancePageReq.getPageNo())
                        .queryParam("pageSize", instancePageReq.getPageSize())
                        .queryParam("accessToken",instancePageReq.getNacosToken())
                        .build())
//                .header("username", userName)
//                .header("password", password)
                .retrieve()
                .bodyToMono(Map.class)
                .map(nacosResponse -> {
                    List<Map> serviceList = (List<Map>) nacosResponse.get("list");
                    serviceList.stream().forEach(service -> {
                        service.put("namespaceId", instancePageReq.getNamespaceId());
                        service.put("groupName", instancePageReq.getGroupName());
                    });

                    Integer total = (Integer) nacosResponse.get("count");

                    // 构建MyBatis-Plus的Page对象
                    Page<Map> page = new Page<>(instancePageReq.getPageNo(), instancePageReq.getPageSize(), total);
                    page.setRecords(serviceList);
                    // 转换为 R 格式
                    return R.success(page);

                }).block(Duration.ofSeconds(5));
    }

    /**
     * 实例下线、上线
     * @param instancePageReq
     * @return
     */
    @ApiOperation(value="实例上线、下线")
    @PostMapping("/instance/op")
    public Mono<R<String>> downInstance(@Valid @RequestBody InstanceInfoReq instancePageReq) {
        String serviceName = instancePageReq.getServiceName();
        if(serviceName.indexOf("@")>0){
            int n = serviceName.lastIndexOf("@");
            serviceName = serviceName.substring(n+1);
        }
        MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
        queryParams.add("serviceName", serviceName);
        queryParams.add("clusterName", instancePageReq.getClusterName());
        queryParams.add("groupName", instancePageReq.getGroupName());
        queryParams.add("ip", instancePageReq.getIp());
        queryParams.add("port", String.valueOf(instancePageReq.getPort()));
        queryParams.add("ephemeral", String.valueOf(instancePageReq.getEphemeral()));
        queryParams.add("weight", String.valueOf(instancePageReq.getWeight()));
        queryParams.add("enabled", String.valueOf(instancePageReq.getEnabled()));
        queryParams.add("metadata", JsonUtil.toJson(instancePageReq.getMetadata()));
        queryParams.add("namespaceId", instancePageReq.getNamespaceId());
        if(StrUtil.isNotBlank(instancePageReq.getNacosToken())){
            queryParams.add("accessToken",instancePageReq.getNacosToken());
        }

        // 转换为 R 格式
        return webClient.put()
                .uri(uriBuilder -> uriBuilder
                        .path("/nacos/v1/ns/instance")
                        .build())
//                .header("username", userName)
//                .header("password", password)
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .body(BodyInserters.fromMultipartData(queryParams))
                .retrieve()
                .bodyToMono(String.class)
                .map(R::success)
                .onErrorResume(e -> {
                    // 错误时返回 R.error
                    return Mono.just(R.error("Nacos操作失败: " + e.getMessage()));
                });
    }

    /**
     * 订阅者列表
     * @param subscriberPageReq
     * @return
     */
    @ApiOperation(value="订阅者列表")
    @PostMapping("/subscriber/page")
    public R pageSubscriber(@Valid @RequestBody SubscriberPageReq subscriberPageReq) {
        if(StrUtil.isEmpty(subscriberPageReq.getNamespaceId())||StrUtil.isEmpty(subscriberPageReq.getServiceName())){
            return R.success(new Page<>(subscriberPageReq.getPageNo(), subscriberPageReq.getPageSize(), 0));
        }
        return webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("/nacos/v1/ns/service/subscribers")
                        .queryParam("serviceName", subscriberPageReq.getServiceName())
                        .queryParam("groupName", subscriberPageReq.getGroupName())
                        .queryParam("namespaceId","back")
                        .queryParam("pageSize", subscriberPageReq.getPageSize())
                        .queryParam("pageNo",subscriberPageReq.getPageNo())
                        .queryParam("accessToken",subscriberPageReq.getNacosToken())
                        .build())
//                .header("username", userName)
//                .header("password", password)
                .retrieve()
                .bodyToMono(Map.class)
                .map(nacosResponse -> {
                    List<Map> serviceList = (List<Map>) nacosResponse.get("subscribers");

                    Integer total = (Integer) nacosResponse.get("count");

                    // 构建MyBatis-Plus的Page对象
                    Page<Map> page = new Page<>(subscriberPageReq.getPageNo(), subscriberPageReq.getPageSize(), total);
                    page.setRecords(serviceList);
                    // 转换为 R 格式
                    return R.success(page);

                }).block(Duration.ofSeconds(5));
    }


}